module OH_LOOP_CONTROL (
   RESET,
   TCLK_155M,
   RCLK_155M,
  // MPI singals
   GLB_VC4_LOOPEN,
   MPI_HDLC_LATENCY,
  // Data Bus interface to HDLC
   DBIN_HDLC_RDEN,
   DBIN_HDLC_RDATA,
 // loop back DataBus Input
   DBIN_RDATA,
   DBIN_RSPE,
   DBIN_RJ1,
   DBIN_RFP,
  // Data Bus interface to OVERHEAD insert
   DOUT_TDATA,
   DOUT_FCNT8,
   DOUT_FCNT270,
   DOUT_FCNT9,
   DOUT_MFCNT64,
   DOUT_PINS_BYPASS
   );

input                 RESET;
input                 TCLK_155M;
input                 RCLK_155M;
input                 GLB_VC4_LOOPEN;
input[3:0]            MPI_HDLC_LATENCY;

output                DBIN_HDLC_RDEN;
input[63:0]           DBIN_HDLC_RDATA;

input[63:0]           DBIN_RDATA;
input                 DBIN_RSPE;
input                 DBIN_RJ1;
input                 DBIN_RFP;

output reg[63:0]      DOUT_TDATA;
output reg[2:0]       DOUT_FCNT8;
output reg[8:0]       DOUT_FCNT270;
output reg[3:0]       DOUT_FCNT9;
output reg[5:0]       DOUT_MFCNT64;
output reg            DOUT_PINS_BYPASS;


// signals for converting DBIN data clock domain to TCLK_155M
reg                   LPCV_RCLK_LOOPEN, LPCV_TCLK_LOOPEN;
reg[7:0]              LPCV_FIFO_WADDR, LPCV_FIFO_RADDR;
wire                  LPCV_FIFO_WEN;
wire[71:0]            LPCV_FIFO_WDATA, LPCV_FIFO_RDATA;
wire[63:0]            LPCV_RDATA;
wire                  LPCV_RSPE;
wire                  LPCV_RJ1;
wire                  LPCV_RFP;
reg[2:0]              LPCV_FCNT8;
reg[8:0]              LPCV_FCNT270;
reg[3:0]              LPCV_FCNT9;
reg[5:0]              LPCV_MFCNT64;
// signals for read payload data 
reg[2:0]              PLRD_FCNT8, PLRD_FCNT8_ME1, PLRD_FCNT8_ME2;
reg[8:0]              PLRD_FCNT270, PLRD_FCNT270_ME1, PLRD_FCNT270_ME2;
reg[3:0]              PLRD_FCNT9, PLRD_FCNT9_ME1, PLRD_FCNT9_ME2;
reg[5:0]              PLRD_MFCNT64, PLRD_MFCNT64_ME1, PLRD_MFCNT64_ME2;
wire[63:0]            PLRD_TDATA_ME2;
reg                   PLRD_PLOAD_EN;
reg[15:0]             PLRD_RDEN_META;
reg[3:0]              PLRD_HDLC_LATENCY;

reg[7:0]              PLRD_FIFO_WADDR, PLRD_FIFO_RADDR;
reg                   PLRD_FIFO_WEN;
wire[71:0]            PLRD_FIFO_WDATA, PLRD_FIFO_RDATA;



//********           DBIN clock domain convert         ********//
// write the DBIN data bus into clock convet FIFO and read out when the GLB_VC4_LOOPEN set to '1'
// keep the FOFI read/write address on reset status when GLB_VC4_LOOPEN set to '0'
// geneate frame counters

always @(posedge RESET or posedge RCLK_155M) begin
   if ( RESET==1'b1 )
      LPCV_RCLK_LOOPEN                 <= 1'b0;
   else
      LPCV_RCLK_LOOPEN                 <= GLB_VC4_LOOPEN;
end
always @(posedge RESET or posedge RCLK_155M) begin
   if ( RESET==1'b1 )
      LPCV_FIFO_WADDR[7:0]             <= 8'd0;
   else begin
      if ( LPCV_RCLK_LOOPEN==1'b1 )
         LPCV_FIFO_WADDR[7:0]          <= LPCV_FIFO_WADDR[7:0] +8'd1;
      else
         LPCV_FIFO_WADDR[7:0]          <= 8'd0;
   end
end
  assign  LPCV_FIFO_WEN            = LPCV_RCLK_LOOPEN;  //only start write when loopback is enabled  
  assign  LPCV_FIFO_WDATA[63:0]    = DBIN_RDATA[63:0];
  assign  LPCV_FIFO_WDATA[64]      = DBIN_RSPE;
  assign  LPCV_FIFO_WDATA[65]      = DBIN_RJ1;
  assign  LPCV_FIFO_WDATA[66]      = DBIN_RFP;
  assign  LPCV_FIFO_WDATA[71:67]   = 5'd0;
  
WRAP_SDP36K_72_72         LPCV_FIFO(
  .CLKA                   ( RCLK_155M ),
  .WEA                    ( LPCV_FIFO_WEN ),
  .ADDRA                  ( LPCV_FIFO_WADDR[7:0] ),
  .DINA                   ( LPCV_FIFO_WDATA[71:0] ),
  .CLKB                   ( TCLK_155M ),
  .ADDRB                  ( LPCV_FIFO_RADDR[7:0] ),
  .DOUTB                  ( LPCV_FIFO_RDATA[71:0] )
   );

always @(posedge RESET or posedge TCLK_155M) begin
   if ( RESET==1'b1 )
      LPCV_TCLK_LOOPEN               <= 1'b0;
   else
      LPCV_TCLK_LOOPEN               <= GLB_VC4_LOOPEN;
end
always @(posedge RESET or posedge TCLK_155M) begin
   if ( RESET==1'b1 )
      LPCV_FIFO_RADDR[7:0]             <= 8'd128;
   else begin
      if ( LPCV_TCLK_LOOPEN==1'b1 )
         LPCV_FIFO_RADDR[7:0]          <= LPCV_FIFO_RADDR[7:0] +8'd1;
      else
         LPCV_FIFO_RADDR[7:0]          <= 8'd128;
   end
end

   assign LPCV_RDATA[63:0]  = LPCV_FIFO_RDATA[63:0];
   assign LPCV_RSPE         = LPCV_FIFO_RDATA[64];
   assign LPCV_RJ1          = LPCV_FIFO_RDATA[65];
   assign LPCV_RFP          = LPCV_FIFO_RDATA[66];

// generate LPCV frame counters
always @(posedge RESET or posedge TCLK_155M) begin
   if ( RESET==1'b1 )
      LPCV_FCNT8[2:0]                     <= 3'd0;
   else begin
      if ( LPCV_RFP==1'b1 )
          LPCV_FCNT8[2:0]                 <= 3'd1;
      else
          LPCV_FCNT8[2:0]                 <= LPCV_FCNT8[2:0] +3'd1;
   end
end
always @(posedge RESET or posedge TCLK_155M) begin
   if ( RESET==1'b1 )
      LPCV_FCNT270[8:0]                   <= 9'd0;
   else begin
      if ( LPCV_RFP==1'b1 ) begin
         LPCV_FCNT270[8:0]                <= 9'd0;
      end
      else if ( LPCV_FCNT8[2:0]==3'b111 ) begin
         if ( LPCV_FCNT270[8:0] ==9'd269 )
            LPCV_FCNT270[8:0]             <= 9'd0;
         else
            LPCV_FCNT270[8:0]             <= LPCV_FCNT270[8:0] +9'd1;
      end
   end
end
always @(posedge RESET or posedge TCLK_155M) begin
   if ( RESET==1'b1 )
      LPCV_FCNT9[3:0]                     <= 4'd0;
   else begin
      if ( LPCV_RFP==1'b1 ) begin
         LPCV_FCNT9[3:0]                  <= 4'd0;
      end
      else if ( LPCV_FCNT8[2:0]==3'b111 && LPCV_FCNT270[8:0] ==9'd269 ) begin
         if ( LPCV_FCNT9[3:0]==4'd8 )
            LPCV_FCNT9[3:0]               <= 4'd0;
         else
            LPCV_FCNT9[3:0]               <= LPCV_FCNT9[3:0] +4'd1;
      end
   end
end
always @(posedge RESET or posedge TCLK_155M) begin
   if ( RESET==1'b1 )
      LPCV_MFCNT64[5:0]                   <= 6'd0;
   else begin
      if ( LPCV_FCNT8[2:0]==3'b111 && LPCV_FCNT270[8:0] ==9'd269 && LPCV_FCNT9[3:0]==4'd8 )
         LPCV_MFCNT64[5:0]                <= LPCV_MFCNT64[5:0] +6'd1;
   end
end




 //******  HDLC data read and control   ********//
 
 // free run frame counter generate
 always @(posedge RESET or posedge TCLK_155M) begin
   if ( RESET==1'b1 )
      PLRD_FCNT8[2:0]               <= 3'd0;
   else begin
      PLRD_FCNT8[2:0]               <= PLRD_FCNT8[2:0] +3'd1;
   end
end
always @(posedge RESET or posedge TCLK_155M) begin
   if ( RESET==1'b1 )
      PLRD_FCNT270[8:0]             <= 9'd0;
   else begin
      if ( PLRD_FCNT8[2:0]==3'b111 ) begin
         if ( PLRD_FCNT270[8:0] ==9'd269 )
            PLRD_FCNT270[8:0]       <= 9'd0;
         else
            PLRD_FCNT270[8:0]       <= PLRD_FCNT270[8:0] +9'd1;
      end
   end
end
always @(posedge RESET or posedge TCLK_155M) begin
   if ( RESET==1'b1 )
      PLRD_FCNT9[3:0]               <= 4'd0;
   else begin
      if ( PLRD_FCNT8[2:0]==3'b111 && PLRD_FCNT270[8:0] ==9'd269 ) begin
         if ( PLRD_FCNT9[3:0]==4'd8 )
            PLRD_FCNT9[3:0]         <= 4'd0;
         else
            PLRD_FCNT9[3:0]         <= PLRD_FCNT9[3:0] +4'd1;
      end
   end
end
always @(posedge RESET or posedge TCLK_155M) begin
   if ( RESET==1'b1 )
      PLRD_MFCNT64[5:0]             <= 6'd0;
   else begin
      if ( PLRD_FCNT8[2:0]==3'b111 && PLRD_FCNT270[8:0] ==9'd269 && PLRD_FCNT9[3:0]==4'd8)
         PLRD_MFCNT64[5:0]          <= PLRD_MFCNT64[5:0] +6'd1;
   end
end


// PLRD_FIFO write control, generate payload enable in VC4-64C mode, and write data into PLRD_FIFO after HDLC read latency
always @(posedge RESET or posedge TCLK_155M) begin
   if ( RESET==1'b1 )
      PLRD_PLOAD_EN                 <= 1'b0;
   else begin
      if ( PLRD_FCNT270[8:0]<9'd10)
         PLRD_PLOAD_EN              <= 1'b0;
      else
         PLRD_PLOAD_EN              <= 1'b1;
   end
end
   assign DBIN_HDLC_RDEN = PLRD_PLOAD_EN;    //output payload enable as HDLC read enable

always @( posedge TCLK_155M ) begin
   PLRD_RDEN_META[15:0]             <= {PLRD_RDEN_META[14:0], PLRD_PLOAD_EN};
end
always @(posedge RESET or posedge TCLK_155M) begin
   if ( RESET==1'b1 )
      PLRD_HDLC_LATENCY[3:0]        <= 4'd0;
   else
      PLRD_HDLC_LATENCY[3:0]        <= MPI_HDLC_LATENCY[3:0];
end
always @( PLRD_HDLC_LATENCY or PLRD_RDEN_META) begin
   case ( PLRD_HDLC_LATENCY )
   4'b0000 : PLRD_FIFO_WEN          <= PLRD_RDEN_META[0];
   4'b0001 : PLRD_FIFO_WEN          <= PLRD_RDEN_META[1];
   4'b0010 : PLRD_FIFO_WEN          <= PLRD_RDEN_META[2];
   4'b0011 : PLRD_FIFO_WEN          <= PLRD_RDEN_META[3];
   4'b0100 : PLRD_FIFO_WEN          <= PLRD_RDEN_META[4];
   4'b0101 : PLRD_FIFO_WEN          <= PLRD_RDEN_META[5];
   4'b0110 : PLRD_FIFO_WEN          <= PLRD_RDEN_META[6];
   4'b0111 : PLRD_FIFO_WEN          <= PLRD_RDEN_META[7];
   4'b1000 : PLRD_FIFO_WEN          <= PLRD_RDEN_META[8];
   4'b1001 : PLRD_FIFO_WEN          <= PLRD_RDEN_META[9];
   4'b1010 : PLRD_FIFO_WEN          <= PLRD_RDEN_META[10];
   4'b1011 : PLRD_FIFO_WEN          <= PLRD_RDEN_META[11];
   4'b1100 : PLRD_FIFO_WEN          <= PLRD_RDEN_META[12];
   4'b1101 : PLRD_FIFO_WEN          <= PLRD_RDEN_META[13];
   4'b1110 : PLRD_FIFO_WEN          <= PLRD_RDEN_META[14];
   4'b1111 : PLRD_FIFO_WEN          <= PLRD_RDEN_META[15];
   default : ;
   endcase
end
always @(posedge RESET or posedge TCLK_155M) begin
   if ( RESET==1'b1 )
      PLRD_FIFO_WADDR[7:0]          <= 8'd0;
   else begin
      if ( PLRD_FIFO_WEN==1'b1 )
         PLRD_FIFO_WADDR[7:0]       <= PLRD_FIFO_WADDR[7:0] +8'd1;
   end
end
   assign  PLRD_FIFO_WDATA[63:0]    = DBIN_HDLC_RDATA[63:0];   // write HDLC data into buffer
   assign  PLRD_FIFO_WDATA[71:64]   = 8'd0;

WRAP_SDP36K_72_72         PLRD_FIFO(
  .CLKA                   ( TCLK_155M ),
  .WEA                    ( PLRD_FIFO_WEN ),
  .ADDRA                  ( PLRD_FIFO_WADDR[7:0] ),
  .DINA                   ( PLRD_FIFO_WDATA[71:0] ),
  .CLKB                   ( TCLK_155M ),
  .ADDRB                  ( PLRD_FIFO_RADDR[7:0] ),
  .DOUTB                  ( PLRD_FIFO_RDATA[71:0] )
   );

// PLRD_FIFO read control and frame counters delay for FIFO lactency
always @(posedge RESET or posedge TCLK_155M) begin
   if ( RESET==1'b1 )
      PLRD_FIFO_RADDR[7:0]          <= 8'd128;
   else begin
      if ( PLRD_FCNT270[8:0]>=9'd10 )
         PLRD_FIFO_RADDR[7:0]       <= PLRD_FIFO_RADDR[7:0] +8'd1;
   end
end

always @(posedge RESET or posedge TCLK_155M) begin
   if ( RESET==1'b1 ) begin
      PLRD_FCNT8_ME1[2:0]           <= 3'd0;
      PLRD_FCNT8_ME2[2:0]           <= 3'd0;
      PLRD_FCNT270_ME1[8:0]         <= 9'd0;
      PLRD_FCNT270_ME2[8:0]         <= 9'd0;
      PLRD_FCNT9_ME1[3:0]           <= 4'd0;
      PLRD_FCNT9_ME2[3:0]           <= 4'd0;
      PLRD_MFCNT64_ME1[5:0]         <= 6'd0;
      PLRD_MFCNT64_ME2[5:0]         <= 6'd0;
   end
   else begin
      PLRD_FCNT8_ME1[2:0]           <= PLRD_FCNT8[2:0];
      PLRD_FCNT8_ME2[2:0]           <= PLRD_FCNT8_ME1[2:0];
      PLRD_FCNT270_ME1[8:0]         <= PLRD_FCNT270[8:0];
      PLRD_FCNT270_ME2[8:0]         <= PLRD_FCNT270_ME1[8:0];
      PLRD_FCNT9_ME1[3:0]           <= PLRD_FCNT9[3:0];
      PLRD_FCNT9_ME2[3:0]           <= PLRD_FCNT9_ME1[3:0];
      PLRD_MFCNT64_ME1[5:0]         <= PLRD_MFCNT64[5:0];
      PLRD_MFCNT64_ME2[5:0]         <= PLRD_MFCNT64_ME1[5:0];
   end
end
   assign PLRD_TDATA_ME2[63:0]  = PLRD_FIFO_RDATA[63:0];


//******** select output data bus from loopback data/normal data bus  ********//
always @(posedge RESET or posedge TCLK_155M) begin
   if ( RESET==1'b1 ) begin
      DOUT_TDATA[63:0]              <= 64'd0;
      DOUT_FCNT8                    <= 3'd0;
      DOUT_FCNT270                  <= 9'd0;
      DOUT_FCNT9                    <= 4'd0;
      DOUT_MFCNT64                  <= 6'd0;
      DOUT_PINS_BYPASS              <= 1'd0;
   end
   else begin
      if ( LPCV_TCLK_LOOPEN==1'b1 ) begin
         DOUT_TDATA[63:0]           <= LPCV_RDATA[63:0];
         DOUT_FCNT8                 <= LPCV_FCNT8[2:0];
         DOUT_FCNT270               <= LPCV_FCNT270[8:0];
         DOUT_FCNT9                 <= LPCV_FCNT9[3:0];
         DOUT_MFCNT64               <= LPCV_MFCNT64[5:0];
         DOUT_PINS_BYPASS           <= 1'd1;
     end
     else begin
         DOUT_FCNT8                 <= PLRD_FCNT8_ME2[2:0];
         DOUT_FCNT270               <= PLRD_FCNT270_ME2[8:0];
         DOUT_FCNT9                 <= PLRD_FCNT9_ME2[3:0];
         DOUT_MFCNT64               <= PLRD_MFCNT64_ME2[5:0];
         DOUT_PINS_BYPASS           <= 1'd0;
         if ( PLRD_FCNT270_ME2[8:0]>=9'd10 )
            DOUT_TDATA[63:0]        <= PLRD_TDATA_ME2[63:0];
         else
            DOUT_TDATA[63:0]        <= 64'd0;
     end
   end
end



endmodule 